home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Franz PD / Franz PD Disk #006 (19xx)(Amiga User Group Deutschland e.V.).zip / Franz PD Disk #006 (19xx)(Amiga User Group Deutschland e.V.).adf / TypeAndTell / TypeAndTell.c < prev    next >
C/C++ Source or Header  |  1986-10-22  |  20KB  |  626 lines

  1. /* TYPE and TELL 
  2.  
  3.    By: Giorgio Galeotti
  4.  
  5.    Anakin Research Inc. 
  6.    Rexdale, Ontatio, Canada.
  7.    Tel. 416-744-4246
  8.  
  9.    This program will install an input device handler before the Intuition
  10.    one, tap all keys typed by the user and spell them out in real time.
  11.  
  12.    Just run this program as a background task. To quit the program press
  13.    "CONTROL LEFT-SHIFT LEFT-ALT RIGHT-AMIGA" at the same time.
  14.  
  15.    This was the result of a couple of days work and it could be improved
  16.    by finding better sounding voices and translations for some of the 
  17.    keys. 
  18.  
  19.    You are free to modify or use this program in any way you want, as long
  20.    as this notice is left here and as long as you do not use the program
  21.    for any commercial purposes. As a matter of fact, you are encouraged to
  22.    improve TYPE & TELL since it could be of some benefit to blind
  23.    Amiga users.
  24.  
  25.    Finally, I and Anakin Research are not responsible for any losses or
  26.    damages caused by this program. After all, it has hardly been tested
  27.    and therefore you should use it at your own risk.
  28.  
  29.    P.S. Writen for Lattice 'C'.
  30. */   
  31.  
  32. #include <exec/types.h>
  33. #include <exec/tasks.h>
  34. #include <exec/nodes.h>
  35. #include <exec/lists.h>
  36. #include <exec/execbase.h>
  37. #include <exec/ports.h>
  38. #include <exec/memory.h>
  39. #include <exec/io.h>
  40. #include <exec/interrupts.h>
  41. #include <exec/devices.h>
  42. #include <exec/libraries.h>
  43. #include <devices/input.h>
  44. #include <devices/inputevent.h>
  45. #include <devices/narrator.h>
  46.  
  47. #include <libraries/translator.h>
  48.  
  49. #include <stdio.h>
  50.  
  51. #include <libraries/dos.h>
  52.  
  53.  
  54. #define INTUITION_REV   0
  55.  
  56. #define INPUT_RING_SIZE 50      /* Size of Input Event ring buffer         */
  57.  
  58. #define QUIT_CODE_1     0x8099  /* Control-shift-alt-alt's event qualifier */
  59. #define QUIT_CODE_2     0x809d  /* As above but with Caps-Lock light on    */
  60.  
  61.  
  62. /*  Globals */
  63.  
  64. struct MsgPort    *InputDevPort      = 0;
  65. struct IOStdReq   *InputRequestBlock = 0;
  66. struct Interrupt  handlerStuff;
  67.  
  68. int               InputDeviceOpen = 0; /* Just to keep track of things       */
  69.  
  70. struct MemEntry   me[10];          /* Dummy data used to keep the handler    */
  71.                                    /* happy                                  */
  72.  
  73. struct InputEvent EventRing[INPUT_RING_SIZE]; /* Raw key events buffer       */
  74. int               Filler  = 0;          /* Pointer into the EventRing Buffer */
  75. int               Emptier = 0;          /*     "            "           "    */
  76. int               Counter = 0;          /* # of entries now in buffer        */
  77.  
  78. ULONG             lastsecond = 0;       /* See myhandler() routine           */
  79. ULONG             lastmicro  = 0;
  80.  
  81. int               MainSignal;         /* Used by handler to wakeup main task */
  82. int               Waiting = 0;        /* Set by main before going to sleep   */
  83. struct Task       *MainTask;
  84.  
  85. extern struct GfxBase *GfxBase;
  86. struct Library *TranslatorBase = 0;
  87. struct Device *ConsoleDevice = 0;
  88. struct narrator_rb *WriteNarrator = 0;
  89.  
  90. extern VOID HandlerInterface();
  91.  
  92. int NarratorDeviceOpen = 0;           /* To keep track of things */
  93.  
  94. struct MsgPort *WritePort = 0;        /* Output Port for Narrator device */
  95.  
  96. UBYTE AudioChannels[4] = {3, 5, 10, 12}; /* Audio channels to recieve output */
  97.  
  98. UBYTE OutputString[100];              /* Translated output string */
  99.  
  100. /******************************************************************************/
  101.  
  102. main()
  103.  
  104. /* The initialization of all resources and a bit more. */
  105.  
  106.  /* For cleanup purposes */
  107.  GfxBase = 0;
  108.  
  109.  /* Open the console device. This will return the InputRequestBlock
  110.     whose field io_Device is initialized to the library pointer.
  111.     See page B-54 in the RKM V2 */
  112.  if ( OpenDevice("console.device",-1,InputRequestBlock,0) != 0 )
  113.     exit(100);
  114.     
  115.  ConsoleDevice = InputRequestBlock->io_Device;
  116.  CloseDevice(InputRequestBlock);
  117.  InputRequestBlock = 0; /* For clean up purposes */
  118.  
  119.  /* Open the Gfx library, since it's needed to do the WaitTOF()'s in the
  120.     input handler */
  121.  if ( (GfxBase = (struct GfxBase *)
  122.                  OpenLibrary("graphics.library",INTUITION_REV)) == 0 )
  123.     CleanUp_Exit(110);
  124.  
  125.  /* Get a signal bit so that our input handler can wake us up when there is 
  126.     something in the buffer */
  127.  MainSignal = AllocSignal(-1);
  128.  MainTask   = (struct Task *)FindTask(0);
  129.  
  130.  /* Get a port for the input device ... */
  131.  InputDevPort = (struct MsgPort *)CreatePort(0,0);
  132.  if ( InputDevPort == NULL )
  133.     CleanUp_Exit(120);
  134.  
  135.  /* ... and an InputRequestBlock */
  136.  InputRequestBlock = (struct IOStdReq *)CreateStdIO(InputDevPort);
  137.  if ( InputRequestBlock == 0 )
  138.     CleanUp_Exit(130);
  139.  
  140.  /* Open the input device */
  141.  if ( OpenDevice("input.device",0,InputRequestBlock,0) == 0 )
  142.     InputDeviceOpen = 1;
  143.  else CleanUp_Exit(140);
  144.  
  145.  /* Get ready to install our own device handler ... */
  146.  handlerStuff.is_Data = (APTR)&me[0];
  147.  handlerStuff.is_Code = HandlerInterface;
  148.  handlerStuff.is_Node.ln_Pri = 51;
  149.  
  150.  InputRequestBlock->io_Command = IND_ADDHANDLER;
  151.  InputRequestBlock->io_Data    = (APTR)&handlerStuff;
  152.  
  153.  /* ... and install the handler */
  154.  DoIO(InputRequestBlock);
  155.  
  156.  /* Open the translator library */
  157.  if ( (TranslatorBase = (struct Library *)
  158.                         OpenLibrary("translator.library",0)) == NULL )
  159.     CleanUp_Exit(500);
  160.  
  161.  /* Open the Narrator device for writes */
  162.  if ( (WritePort = (struct MsgPort *)CreatePort(0,0)) == NULL )
  163.     CleanUp_Exit(510);
  164.  
  165.  WriteNarrator = (struct narrator_rb *)
  166.                  CreateExtIO(WritePort,sizeof(struct narrator_rb));
  167.  if ( WriteNarrator == NULL )
  168.     CleanUp_Exit(520);
  169.  
  170.  if ( OpenDevice("narrator.device",0,WriteNarrator,0) == 0 )
  171.     NarratorDeviceOpen = 1;
  172.  else CleanUp_Exit(140);
  173.  
  174.  /* Set up part of the narrator's WritePort */
  175.  WriteNarrator->ch_masks           = (AudioChannels);
  176.  WriteNarrator->nm_masks           = sizeof(AudioChannels);
  177.  WriteNarrator->message.io_Command = CMD_WRITE;
  178.  
  179.  /* Call the main control routine and sit there until the user requests to 
  180.     quit. */
  181.  TheBigLoop();
  182. }
  183.  
  184. /****************************************************************************/
  185.  
  186. TheBigLoop()
  187.  
  188. /* This routine contains the loop that keeps checking everything the user does 
  189.    at the keyboard so that appropiate actions can be taken. */
  190.  
  191. { BYTE  buffer[30]; /* Buffer used by RawKeyConvert() to put results in. */
  192.   int   actual;     /* # of bytes returned by RawKeyConvert().          */
  193.   UWORD Qualifier;
  194.  
  195.  while ( 1 )
  196.        {
  197.         /* Anything in the buffer ? */
  198.         if ( Counter == 0 )
  199.            {
  200.             /* No ... Go to sleep, waiting for the input handler to wake
  201.                us up */
  202.             Waiting = 1;
  203.             Wait(1<<MainSignal);
  204.            }
  205.  
  206.         Qualifier = EventRing[Emptier].ie_Qualifier;
  207.  
  208.         /* User requested to quit Type&Tell ? */
  209.         if ( Qualifier == QUIT_CODE_1 || Qualifier == QUIT_CODE_2 )
  210.            CleanUp_Exit(1000);
  211.  
  212.         /* Convert raw-key event to ANSI standard. Assume default keymap. */
  213.         actual = RawKeyConvert(&EventRing[Emptier],buffer,30,0);
  214.  
  215.         if ( actual == 1 )
  216.            SpeakASCII(buffer,actual);
  217.  
  218.         else SpeakQualifier(&EventRing[Emptier]);
  219.  
  220.         /* Buffer wrap ? */
  221.         if ( Emptier == INPUT_RING_SIZE-1 )
  222.            Emptier = 0;
  223.         else ++Emptier;
  224.  
  225.         /* One less event in the buffer ... */
  226.         --Counter;
  227.        }
  228. }
  229.  
  230. /****************************************************************************/
  231.  
  232. SpeakASCII(buffer,actual)
  233.  
  234. /* Speak the ASCII character contained in buffer and whose lenght is in 
  235.    actual. */
  236.  
  237. char    *buffer;
  238. int     actual;
  239.  
  240.  if ( actual == 1 )
  241.     if ( (buffer[0] >= 'A' && buffer[0] <= 'Z') ||
  242.          (buffer[0] >= '0' && buffer[0] <= '9') )
  243.        {
  244.         WriteNarrator->rate     = DEFRATE+100;
  245.         WriteNarrator->pitch    = DEFPITCH;
  246.         WriteNarrator->mode     = NATURALF0;
  247.         WriteNarrator->sex      = DEFSEX;
  248.         WriteNarrator->volume   = DEFVOL;
  249.         WriteNarrator->sampfreq = DEFFREQ;
  250.  
  251.         /* Translate the character */
  252.         Translate(buffer,1,OutputString,100);
  253.  
  254.         WriteNarrator->message.io_Data = (APTR)OutputString;
  255.         WriteNarrator->message.io_Length = strlen(OutputString);
  256.  
  257.         /* And speak it */
  258.         DoIO(WriteNarrator);
  259.     
  260.         return;
  261.        }
  262.  
  263.     else if ( buffer[0] >= 'a' && buffer[0] <= 'z' )
  264.             {
  265.              WriteNarrator->rate     = DEFRATE+100;
  266.              WriteNarrator->pitch    = DEFPITCH+50;
  267.              WriteNarrator->mode     = NATURALF0;
  268.              WriteNarrator->sex      = FEMALE;
  269.              WriteNarrator->volume   = DEFVOL;
  270.              WriteNarrator->sampfreq = DEFFREQ;
  271.  
  272.              /* Translate the character */
  273.              Translate(buffer,1,OutputString,100);
  274.  
  275.              WriteNarrator->message.io_Data = (APTR)OutputString;
  276.              WriteNarrator->message.io_Length = strlen(OutputString);
  277.  
  278.              /* And speak it */
  279.              DoIO(WriteNarrator);
  280.     
  281.              return;
  282.             }
  283.     
  284.          else {
  285.                WriteNarrator->rate     = DEFRATE+100;
  286.                WriteNarrator->pitch    = DEFPITCH;
  287.                WriteNarrator->mode     = NATURALF0;
  288.                WriteNarrator->sex      = DEFSEX;
  289.                WriteNarrator->volume   = DEFVOL;
  290.                WriteNarrator->sampfreq = DEFFREQ;
  291.  
  292.                /* See if it is a control character */
  293.                if ( buffer[0] >= 0x01 && buffer[0] <= 0x1a )
  294.                   {
  295.                    buffer[8] = buffer[0] + 0x40;
  296.                    strcpy(buffer,"CONTROL");
  297.                    buffer[7] = ' ';
  298.                    Translate(buffer,9,OutputString,100);
  299.                   }
  300.  
  301.                else switch ( buffer[0] )
  302.                     {
  303.                      case 0x1b:Translate("ESCAPE",6,OutputString,100);
  304.                                break;
  305.  
  306.                      case ' ': Translate("SPACE",5,OutputString,100);
  307.                                break;
  308.  
  309.                      case '!': Translate("EXCLAMATION",11,OutputString,100);
  310.                                break;
  311.  
  312.                      case '"': Translate("DOUBLE QUOTE",12,OutputString,100);
  313.                                break;
  314.  
  315.                      case '#': Translate("SHARP",5,OutputString,100);
  316.                                break;
  317.  
  318.                      case '$': Translate("DOLLAR",6,OutputString,100);
  319.                                break;
  320.  
  321.                      case '%': Translate("PERCENT",7,OutputString,100);
  322.                                break;
  323.  
  324.                      case '&': Translate("AND",3,OutputString,100);
  325.                                break;
  326.  
  327.                      case '\'':Translate("RIGHT QUOTE",11,OutputString,100);
  328.                                break;
  329.  
  330.                      case '(': Translate("LEFT PARENTHESIS",16,OutputString,100);
  331.                                break;
  332.  
  333.                      case ')': Translate("RIGHT PARENTHESIS",17,OutputString,100);
  334.                                break;
  335.  
  336.                      case '*': Translate("STAR",4,OutputString,100);
  337.                                break;
  338.  
  339.                      case '+': Translate("PLUS",4,OutputString,100);
  340.                                break;
  341.  
  342.                      case ',': Translate("COMMA",5,OutputString,100);
  343.                                break;
  344.  
  345.                      case '-': Translate("MYNUS",5,OutputString,100);
  346.                                break;
  347.  
  348.                      case '.': Translate("DOT",3,OutputString,100);
  349.                                break;
  350.  
  351.                      case '/': Translate("SLASH",5,OutputString,100);
  352.                                break;
  353.  
  354.                      case ':': Translate("COLON",5,OutputString,100);
  355.                                break;
  356.  
  357.                      case ';': Translate("SEMI COLON",10,OutputString,100);
  358.                                break;
  359.  
  360.                      case '<': Translate("LESS THAN",9,OutputString,100);
  361.                                break;
  362.  
  363.                      case '>': Translate("GREATER THAN",12,OutputString,100);
  364.                                break;
  365.  
  366.                      case '=': Translate("EQUAL",5,OutputString,100);
  367.                                break;
  368.  
  369.                      case '?': Translate("QUESTION",8,OutputString,100);
  370.                                break;
  371.  
  372.                      case '@': Translate("AT",2,OutputString,100);
  373.                                break;
  374.  
  375.                      case '[': Translate("LEFT BRACKET",12,OutputString,100);
  376.                                break;
  377.  
  378.                      case '\\':Translate("BACKSLASH",9,OutputString,100);
  379.                                break;
  380.  
  381.                      case ']': Translate("RIGHT BRACKET",13,OutputString,100);
  382.                                break;
  383.  
  384.                      case '^': Translate("CARROT",6,OutputString,100);
  385.                                break;
  386.  
  387.                      case '_': Translate("UNDER SCORE",11,OutputString,100);
  388.                                break;
  389.  
  390.                      case '`': Translate("LEFT QUOTE",10,OutputString,100);
  391.                                break;
  392.  
  393.                      case '{': Translate("LEFT BRACE",10,OutputString,100);
  394.                                break;
  395.  
  396.                      case '|': Translate("VERTICAL BAR",12,OutputString,100);
  397.                                break;
  398.  
  399.                      case '}': Translate("RIGHT BRACE",11,OutputString,100);
  400.                                break;
  401.  
  402.                      case '~': Translate("TILDA",5,OutputString,100);
  403.                                break;
  404.  
  405.                      case 0x7f:Translate("DELETE",6,OutputString,100);
  406.                                break;
  407.  
  408.                      default: return;
  409.                     }
  410.    
  411.                WriteNarrator->message.io_Data = (APTR)OutputString;
  412.                WriteNarrator->message.io_Length = strlen(OutputString);
  413.                /* And speak it */
  414.                DoIO(WriteNarrator);
  415.      
  416.                return;
  417.               }
  418. }     
  419.  
  420. /****************************************************************************/
  421.  
  422. SpeakQualifier(Event)
  423.  
  424. /* The keystroke did not translate to any ASCII character, but nevertheless
  425.    it must be called out */
  426.  
  427. struct InputEvent *Event;
  428.  
  429. {
  430.  WriteNarrator->rate     = DEFRATE+100;
  431.  WriteNarrator->pitch    = DEFPITCH+100;
  432.  WriteNarrator->mode     = NATURALF0;
  433.  WriteNarrator->sex      = FEMALE;
  434.  WriteNarrator->volume   = DEFVOL;
  435.  WriteNarrator->sampfreq = DEFFREQ;
  436.  
  437.  switch ( Event->ie_Code )
  438.         {
  439.          case 0x50: Translate("FUNCTION 1",10,OutputString,100);
  440.                     break;
  441.  
  442.          case 0x51: Translate("FUNCTION 2",10,OutputString,100);
  443.                     break;
  444.  
  445.          case 0x52: Translate("FUNCTION 3",10,OutputString,100);
  446.                     break;
  447.  
  448.          case 0x53: Translate("FUNCTION 4",10,OutputString,100);
  449.                     break;
  450.  
  451.          case 0x54: Translate("FUNCTION 5",10,OutputString,100);
  452.                     break;
  453.  
  454.          case 0x55: Translate("FUNCTION 6",10,OutputString,100);
  455.                     break;
  456.  
  457.          case 0x56: Translate("FUNCTION 7",10,OutputString,100);
  458.                     break;
  459.  
  460.          case 0x57: Translate("FUNCTION 8",10,OutputString,100);
  461.                     break;
  462.  
  463.          case 0x58: Translate("FUNCTION 9",10,OutputString,100);
  464.                     break;
  465.  
  466.          case 0x59: Translate("FUNCTION TEN",12,OutputString,100);
  467.                     break;
  468.  
  469.          case 0x63: Translate("CONTROL",7,OutputString,100);
  470.                     break;
  471.  
  472.          case 0x60:
  473.          case 0x61: Translate("SHIFT",5,OutputString,100);
  474.                     break;
  475.  
  476.          case 0x64:
  477.          case 0x65: Translate("ALTERNATE",9,OutputString,100);
  478.                     break;
  479.  
  480.          case 0x66: Translate("LEFT AMIGA",10,OutputString,100);
  481.                     break;
  482.  
  483.          case 0x67: Translate("RIGHT AMIGA",11,OutputString,100);
  484.                     break;
  485.  
  486.          case 0x5f: Translate("HELP",4,OutputString,100);
  487.                     break;
  488.  
  489.          case 0x4c: Translate("GO UP",5,OutputString,100);
  490.                     break;
  491.  
  492.          case 0x4f: Translate("GO LEFT",7,OutputString,100);
  493.                     break;
  494.  
  495.          case 0x4e: Translate("GO RIGHT",8,OutputString,100);
  496.                     break;
  497.  
  498.          case 0x4d: Translate("GO DOWN",7,OutputString,100);
  499.                     break;
  500.  
  501.          case 0x62: Translate("CAPS LOCK ON",12,OutputString,100);
  502.                     break;
  503.  
  504.          case 0xe2: Translate("CAPS LOCK OFF",13,OutputString,100);
  505.                     break;
  506.  
  507.          default: return;
  508.         }
  509.    
  510.  WriteNarrator->message.io_Data = (APTR)OutputString;
  511.  WriteNarrator->message.io_Length = strlen(OutputString);
  512.  /* And speak it */
  513.  DoIO(WriteNarrator);
  514. }
  515.  
  516. /****************************************************************************/
  517.  
  518. CleanUp_Exit(exitlevel)
  519.  
  520. /* Clean up all allocated resources and exit */
  521.  
  522. int exitlevel;
  523.  
  524. {
  525.  /* Remove our input handler and device from the chain */ 
  526.  if ( InputRequestBlock )
  527.     {
  528.      InputRequestBlock->io_Command = IND_REMHANDLER;
  529.      InputRequestBlock->io_Data    = (APTR)&handlerStuff;
  530.      DoIO(InputRequestBlock);
  531.      
  532.      if ( InputDeviceOpen )
  533.         CloseDevice(InputRequestBlock);
  534.  
  535.      DeleteStdIO(InputRequestBlock);
  536.     }
  537.  
  538.  if ( InputDevPort )
  539.     DeletePort(InputDevPort);
  540.  
  541.  if ( NarratorDeviceOpen )
  542.     CloseDevice(WriteNarrator);
  543.  
  544.  if ( WriteNarrator )
  545.     DeleteExtIO(WriteNarrator,sizeof(struct narrator_rb));
  546.  
  547.  if ( TranslatorBase )
  548.     CloseLibrary(TranslatorBase);
  549.  
  550.  if ( WritePort )
  551.     DeletePort(WritePort);
  552.  
  553.  if ( GfxBase )
  554.     CloseLibrary(GfxBase);
  555.  
  556.  exit(exitlevel);
  557. }
  558.  
  559. /****************************************************************************/
  560.  
  561. struct InputEvent *myhandler(ev,mydata)
  562.  
  563. /* This input handler inserts itself at a higher priority than the intuition
  564.    handler. It will intercept all raw-key events and put them into the ring-
  565.    buffer so that other tasks in this program can use the data to keep track 
  566.    of what keys have been pressed by the user ... */
  567.  
  568. struct InputEvent *ev;
  569. struct MemEntry   *mydata[];
  570.  
  571. { register struct InputEvent *NextEvent;
  572.  
  573. /*  look at all events in the event-list (or whatever it's called) and
  574.     put in the buffer all raw-key events whose time stamp indicates
  575.     we haven't looked at them before. Hopefully the system links new events
  576.     at the end of the chain, so that all time stamps are in order. */
  577.  
  578.  NextEvent = ev;   /* First entry in event-list */
  579.  do {
  580.      if ( NextEvent->ie_Class == IECLASS_RAWKEY )
  581.         if ( ( NextEvent->ie_TimeStamp.tv_micro > lastmicro &&
  582.                NextEvent->ie_TimeStamp.tv_secs >= lastsecond ) ||
  583.                NextEvent->ie_TimeStamp.tv_secs >  lastsecond )
  584.            {
  585.             lastmicro  = NextEvent->ie_TimeStamp.tv_micro;
  586.             lastsecond = NextEvent->ie_TimeStamp.tv_secs;
  587.  
  588.             /* Get our own copy of the event */
  589.             movmem(NextEvent,&EventRing[Filler],sizeof(struct InputEvent));
  590.  
  591.             ++Counter;    /* One more item in the buffer */
  592.  
  593.             /* Buffer Wrap ? */
  594.             if ( Filler == INPUT_RING_SIZE-1 )
  595.                Filler = 0;
  596.             else ++Filler;
  597.  
  598.             /* Is the user of the buffer waiting ? */
  599.             if ( Waiting )
  600.                {
  601.                 Signal(MainTask,1<<MainSignal);
  602.                 Waiting = 0;
  603.                }
  604.  
  605.             /* The buffer may fill in final program. In case that
  606.                it happens, do some waits to give the other tasks the time 
  607.                to empty the buffer a bit. A completely busy loop would tie up
  608.                the system forever. */
  609.             while ( Counter >= INPUT_RING_SIZE - 2 )
  610.                   {
  611.                    WaitTOF();
  612.                    WaitTOF();
  613.                    WaitTOF();
  614.                   } 
  615.            }
  616.  
  617.      NextEvent = NextEvent->ie_NextEvent;
  618.     }
  619.     while ( NextEvent );    /* Done ? */
  620.  
  621.  return ( ev );
  622. }
  623.  
  624.